package com.aleyn.processor

import com.aleyn.processor.generator.generatorClass
import com.aleyn.processor.generator.generatorModule
import com.aleyn.processor.scanner.LRouterMetaDataScanner
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.symbol.KSAnnotated

/**
 * @author: Aleyn
 * @date: 2023/6/13 18:51
 *
 * KSP (Kotlin Symbol Processing) 的入口，用于提供 [RouterSymbolProcessor] 实例。
 *
 * [SymbolProcessorProvider] 是 KSP 提供的一个服务接口 (SPI)。
 * 在编译期间，KSP 会查找所有实现了这个接口的类，并调用其 `create` 方法来获取一个 [SymbolProcessor] 实例。
 * 这个实例将用于处理注解和生成代码。
 */
private const val L_ROUTER_MODULE_NAME = "L_ROUTER_MODULE_NAME"

/**
 * 核心的 KSP 注解处理器。
 *
 * 这个类负责整个路由框架在编译期的代码生成任务。它的主要工作流程如下：
 * 1. **扫描符号 (Scanning)**: 使用 [LRouterMetaDataScanner] 扫描所有被 `@Route`, `@Autowired` 等注解标记的类和属性。
 * 2. **数据处理 (Processing)**: 将扫描到的信息封装成元数据模型 (`RouterMetaData`, `InjectMetaData` 等)。
 * 3. **代码生成 (Code Generation)**: 根据收集到的元数据，使用 [CodeGenerator] 生成两类关键代码：
 *    - **依赖注入辅助类**: 为每个需要依赖注入的 Activity/Fragment 生成一个 `$$Inject` 后缀的辅助类，用于执行字段赋值。
 *    - **模块路由注册类**: 为每个 Gradle 模块生成一个 `LRouter$$` 后缀的类，该类负责注册当前模块的所有路由信息。
 *
 * @param codeGenerator KSP 提供的代码生成器，用于创建新的源文件。
 * @param logger KSP 提供的日志记录器，用于在编译过程中输出信息。
 * @param options 从 Gradle 插件传递过来的配置选项，例如模块名。
 */
class RouterSymbolProcessor(
    private val codeGenerator: CodeGenerator,
    private val logger: KSPLogger,
    options: Map<String, String>,
) : SymbolProcessor {

    /**
     * 从 Gradle 插件获取当前模块的名称，用于生成模块路由注册类。
     */
    private val moduleName = options[L_ROUTER_MODULE_NAME]

    /**
     * 符号扫描器，负责查找和解析 LRouter 相关的注解。
     */
    private val metaDataScanner = LRouterMetaDataScanner(logger)

    /**
     * KSP 的核心处理方法，每一轮 (round) 注解处理都会被调用。
     *
     * @param resolver KSP 解析器，提供了访问和查询项目中所有符号（类、函数、属性等）的能力。
     * @return 返回一个列表，其中包含无法被处理或处理失败的符号。这些符号会在下一轮处理中被再次传递进来。
     *         如果所有符号都已成功处理，则返回一个空列表。
     */
    override fun process(resolver: Resolver): List<KSAnnotated> {
        logger.logging("LRouter start check symbols")

        // 步骤 1: 使用扫描器扫描所有符号，并返回任何无效的符号。
        val invalidSymbols = metaDataScanner.scanSymbols(resolver)

        // 如果存在无效符号，则直接返回，等待下一轮处理。
        if (invalidSymbols.isNotEmpty()) return invalidSymbols

        logger.logging("LRouter start handle")

        // 步骤 2: 处理扫描到的`@Autowired`注解，并为每个目标类生成依赖注入辅助类。
        metaDataScanner.getAutowiredDeclaration().forEach {
            it.generatorClass(codeGenerator, logger)
        }

        // 步骤 3: 处理扫描到的`@Route`注解，并为当前模块生成路由注册类。
        metaDataScanner.getModuleDeclaration()
            .generatorModule(codeGenerator, logger, moduleName)

        // 所有符号处理完毕，返回空列表。
        return emptyList()
    }
}


/**
 * [SymbolProcessor] 的服务提供者 (Provider)。
 *
 * KSP 通过 `META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider` 文件找到这个类，
 * 并通过调用 [create] 方法来实例化 [RouterSymbolProcessor]。
 */
class RouterProcessorProvider : SymbolProcessorProvider {
    /**
     * 创建一个 [RouterSymbolProcessor] 实例。
     *
     * @param environment KSP 提供的环境信息，包含了 [codeGenerator], [logger], [options] 等核心组件。
     * @return 返回一个配置好的 [RouterSymbolProcessor] 实例。
     */
    override fun create(
        environment: SymbolProcessorEnvironment
    ): SymbolProcessor {
        return RouterSymbolProcessor(
            environment.codeGenerator,
            environment.logger,
            environment.options
        )
    }
}



